package com.rssreader.client.lists;

import java.util.Arrays;
import java.util.List;

import com.extjs.gxt.ui.client.Registry;
import com.extjs.gxt.ui.client.data.BaseListLoader;
import com.extjs.gxt.ui.client.data.BeanModel;
import com.extjs.gxt.ui.client.data.BeanModelFactory;
import com.extjs.gxt.ui.client.data.BeanModelLookup;
import com.extjs.gxt.ui.client.data.BeanModelReader;
import com.extjs.gxt.ui.client.data.ListLoadResult;
import com.extjs.gxt.ui.client.data.ListLoader;
import com.extjs.gxt.ui.client.data.RpcProxy;
import com.extjs.gxt.ui.client.dnd.DragSource;
import com.extjs.gxt.ui.client.event.DNDEvent;
import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
import com.extjs.gxt.ui.client.event.SelectionChangedListener;
import com.extjs.gxt.ui.client.mvc.Dispatcher;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.Info;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.form.ListField;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.rssreader.client.RSSReaderConstants;
import com.rssreader.client.mvc.events.AppEvents;
import com.rssreader.client.services.FeedServiceAsync;
import com.rssreader.shared.model.Feed;

public class FeedList extends LayoutContainer {

    // create a new ListFieid
    private final ListField<BeanModel> feedList = new ListField<BeanModel>();

    private ListLoader<ListLoadResult<BeanModel>> loader;

    // 啟動時調用loadFeedList方法，從XML文件中檢索其內容，
    // 儲存到store當中去，讓FeedList component顯示出來store的內容
    public FeedList() {
	setLayout(new FitLayout());

	final FeedServiceAsync feedService = Registry
		.get(RSSReaderConstants.FEED_SERVICE);
	feedService.loadFeedList(false, new AsyncCallback<List<Feed>>() {

	    // FeedServiceImpl實作回傳list型別，故可以用size取得list數
	    @Override
	    public void onSuccess(List<Feed> result) {
		Info.display("RSS Reader", "Feed loadFeedList successfully size: "
			+ result.size());

		// 按下save跟add的執行動作類似，ListStore重新讀取feeds.txt中URL
		final ListStore<BeanModel> feedStore = Registry
			.get(RSSReaderConstants.FEED_STORE);
		for (Feed feed : result) {
		    BeanModelFactory beanModelFactory = BeanModelLookup.get()
			    .getFactory(feed.getClass());
		    feedStore.add(beanModelFactory.createModel(feed));
		}
	    }

	    @Override
	    public void onFailure(Throwable caught) {
		Info.display("RSS Reader", "Failed to loadFeedList");
	    }
	});
    }

    @Override
    protected void onRender(Element parent, int index) {
	super.onRender(parent, index);

	// 　１：從Registry裡獲得Service
	final FeedServiceAsync feedService = (FeedServiceAsync) Registry
		.get(RSSReaderConstants.FEED_SERVICE);

	// 　２：定義RpcProxy，在load方法裡透過FeedService的loadFeedList方法取得Feed物件的List
	RpcProxy<List<Feed>> proxy = new RpcProxy<List<Feed>>() {

	    @Override
	    protected void load(Object loadConfig, AsyncCallback<List<Feed>> callback) {
		// loadFeedList的第一個參數表示有／無children data
		feedService.loadFeedList(false, callback);
	    }
	};

	// 　３：定義Reader，新增一個BeanModelReader的實體去將Feed物件轉換成BeanModel物件
	BeanModelReader reader = new BeanModelReader();

	// 　４：新增一個ListLoader，將RpcProxy和BeanModelReader傳入，並透過他們讀取BeanModel的list中，Feed物件的呈現
	loader = new BaseListLoader<ListLoadResult<BeanModel>>(proxy, reader);

	// retrieve the feed store from the Registry
	// final ListStore<BeanModel> feedStore =
	// Registry.get(RSSReaderConstants.FEED_STORE);
	// 重新定義ListStore，使用ListLoader當作參數讓loader去填滿store
	// 　５：傳入loader，生成store，此時還沒有load數據
	ListStore<BeanModel> feedStore = new ListStore<BeanModel>(loader);

	// set the feed store as the Store for the feed list ListField
	// tell the ListField to use the title field of the Feed object
	// as the value to display in the ListField
	// 　６：將store綁到data-backed component上
	feedList.setStore(feedStore); // 改成由Registry的feed Service取得

	// tell the ListField to use the title field
	// of the Feed object as the value to display in the ListField
	// 替換setDisplayField方法-------------feedList.setDisplayField("title");
	feedList.setTemplate(getTemplate());

	// 當list被選取時，負責轉發FeedSelected事件並加載feed物件
	feedList.addSelectionChangedListener(new SelectionChangedListener<BeanModel>() {

	    @Override
	    public void selectionChanged(SelectionChangedEvent<BeanModel> se) {
		Feed feed = se.getSelectedItem().getBean();
		if (feed != null) {
		    Dispatcher.forwardEvent(AppEvents.FeedSelected, feed);
		}
	    }
	});

	// 　７：真正的load數據，load成功後，data-backed component會自動地顯示出來
	loader.load();

	// 新建DragSource包裝feedList，並將其選中的object傳到DNDEvent（可能為多個）
	DragSource source = new DragSource(feedList) {
	    @Override
	    protected void onDragStart(DNDEvent event) {
		event.setData(feedList.getSelection());
	    }
	};
	source.setGroup(RSSReaderConstants.FEED_DD_GROUP);

	// Add the ListField to the underlying container
	add(feedList);
    }

    // returns the Template content as a String
    private String getTemplate() {
	// use <tpl> tag to process each of the data objects in the store
	StringBuilder sb = new StringBuilder();
	sb.append("<tpl for=\".\">");
	// the entry in the list to be made up of the title of the feed in bold
	// list列表只顯示title以及description，並將title的格式設為粗體
	sb.append("<div class='x-combo-list-item'><b>{title}</b>-{description}</div>");
	sb.append("</tpl>");
	return sb.toString();
    }

    public void reloadFeeds() {
	loader.load();
    }

    // 使用feed參數去選中list中的ListField
    public void selectFeed(Feed feed) {
	BeanModelFactory beanModelFactory = BeanModelLookup.get().getFactory(
		feed.getClass());
	feedList.setSelection(Arrays.asList(beanModelFactory.createModel(feed)));
    }
}
